package com.tx.admin.util.common;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.persistence.Entity;

import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.tx.admin.core.entity.SuperEntity;
import com.tx.admin.core.entity.TreeEntity;
import com.tx.admin.core.anno.JpaKey;

import io.swagger.annotations.ApiModel;

/**
 * 代码生成器工具
 * @author 22155
 *
 */
public class GeneratorUtil {

	static {
		//设置资源加载器
		Properties prop = new Properties();
	    prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");   
	    prop.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
        prop.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        prop.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");     
	    Velocity.init(prop);
	}
	
	//文件资源所在地
	private static final String templateResource = "template/java/";

	
	/**
	 * 
	 * @param clazz 指定实体类型
	 * @param templateName 模板名称
	 * @return 生成的代码
	 * @throws IOException 
	 */
	public static String generatorCode(Class clazz,String templateName) throws IOException {
		Map<String,Object> args = getEntityArgs(clazz);
        String template =templateResource+templateName;
	    StringWriter sw = new StringWriter();
	
        Template tpl = Velocity.getTemplate(template, "UTF-8");
        VelocityContext context = new VelocityContext(args);
        tpl.merge(context, sw);
        return sw.toString();
	}

	/**
	 * 将指定模板代码添加到压缩流中
	 * @param clazz 类对象
	 * @param out 压缩文件流
	 * @throws IOException
	 */
	public static void generatorCodeZip(Class clazz,ZipOutputStream out ) throws IOException {

		Resource resource = new ClassPathResource(templateResource);
		File folder= resource.getFile();
		for(File template : folder.listFiles()) {
				//得到模板类型

			Map<String,Object> entityArgs = getEntityArgs(clazz);
			Map<String,Object>  templateArgs = getTemplatArgs(template);
			Map<String,Object>  map = new HashMap<>();
			map.putAll(templateArgs);
			map.putAll(entityArgs);

			String name = "java/"+entityArgs.get("modulesName")+"/"+templateArgs.get("modulesName")+ "/"+entityArgs.get("entityName")+templateArgs.get("entityName") +templateArgs.get("modulesType");
			String code = generatorCode(clazz,template.getName());
			out.putNextEntry(new ZipEntry(name));
			IOUtils.write(code, out, "UTF-8");
	    }
	}
	


	public static void generatorCodeZips(String outZipPath,List<File> moduleFiles) throws IOException, ClassNotFoundException {
		FileOutputStream fileOutputStream = new FileOutputStream(outZipPath);
		ZipOutputStream out = new ZipOutputStream(fileOutputStream);
		for(File moduleFile:moduleFiles) {
			moduleFile = new File(moduleFile.getPath()+"/entity");

			for(File file : moduleFile.listFiles()) {

				Class clazz = ClassUtil.fileToClass(file);
				Entity e = AnnotationUtils.findAnnotation(clazz,Entity.class);
				if(e == null){
					continue;
				}
				generatorCodeZip(clazz,out);
			}
		}
	
		IOUtils.closeQuietly(out);
	}

	
	public static Map<String,Object> getTemplatArgs(File file) {
		Map<String,Object> map = new HashMap<String,Object>();
		
		String name = file.getName();
		for(String str:Arrays.asList(".vue",".java")) {
			int ind = name.indexOf(str);
			if(ind != -1) {
				String modulesName= "";
				String entityName = "";
				String[] names=name.substring(0,ind).split("\\.");
				for(int x = 0;x<names.length;x++) {
					modulesName+=names[x];
					entityName+=StringUtil.toUpperCaseFirstOne(names[x]);
					if(x !=names.length -1) {
						modulesName+="/";
					}
				}
				map.put("modulesName", modulesName);
				map.put("modulesType", str);
				map.put("entityName", entityName);
				System.out.println(modulesName);
				return map;
			}
		}
		
		return map;
	}
	
	
	
	/**
	 * 得到实体自带的参数
	 * @param clazz
	 * @return
	 * @throws IOException 
	 */
	public static Map<String,Object> getEntityArgs(Class clazz) throws IOException{

		List<Field> contantFields = new LinkedList<>();
		for (Field field : clazz.getDeclaredFields()) {
			JpaKey jpaKey = field.getAnnotation(JpaKey.class);
			if(jpaKey != null && jpaKey.content()){
				contantFields.add(field);
			}
		}

		ApiModel apiModel = AnnotationUtils.findAnnotation(clazz,ApiModel.class);
		if(apiModel == null){
			throw new RuntimeException(clazz+"api缺少注解");
		}
		Map<String,Object> map = new HashMap<>();
		map.put("name",apiModel.value());
		map.put("contantFields",contantFields);
		String modulesName = ClassUtil.classToFile(clazz).getParentFile().getParentFile().getName();
	
		String className = clazz.getSimpleName();
		String name =  className.substring(0, className.length()-6);
		
		String entityName = StringUtil.toUpperCaseFirstOne(name);;

		String requestMapping=StringUtil.toLowerCaseFirstOne(entityName);
		//类名
		map.put("className", className);
		map.put("modulesName", modulesName);
		//实体名
		map.put("entityName", entityName);

		map.put("entityTitle", requestMapping);
		map.put("requestMapping",requestMapping );
		String parentClass="";
		if(TreeEntity.class.isAssignableFrom(clazz)) {
			parentClass="Tree";
		}else if(SuperEntity.class.isAssignableFrom(clazz)) {
			parentClass="Super";
		}
		else {
			throw new RuntimeException("实体必须继承"+SuperEntity.class);
		}
		map.put("parentClass", parentClass);
		
		
		return map;
	}



	
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		//List<String> moduleNames= getEntityModules();
		//String code = generatorCode(UserEntity.class,"SuperController");
		//zip(code,"controller");
		//System.out.println(getMoules(UserEntity.class));
		List<File> modules = ClassUtil.getModules();
		//System.out.println(SuperConstant.SuperEnum.class.isAssignableFrom(RoleConstant.RoleTypeEnum.class));
		generatorCodeZips("E:\\code.zip",modules);
		//System.out.println(getFileType("SuperApi.java.vm"));
		//System.out.println(getEntityArgs(UserEntity.class));

		
	}
}
